/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "rtctime.h"
#include "dataproc.h"

static int16_t rtc_year_base = 2000;

void rtc_year_base_set(int16_t year)
{
	rtc_year_base = year;
}


int16_t rtc_year_base_get(void)
{
	return rtc_year_base;
}

/*****************************************************************************/ /*!
* @brief   Rtc run .
*          once per sec , in timer int
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void TimeRun(TIME_Type *TimeCur)
{
	uint8_t mon, day, hour, min, sec, week;
	uint16_t year;

	year = TimeCur->year;
	mon = TimeCur->mon;
	day = TimeCur->day;
	hour = TimeCur->hour;
	min = TimeCur->min;
	sec = TimeCur->sec;
	week = TimeCur->week;

	sec++;

	if (sec > 59)
	{
		sec = 0;
		min++;
	}

	if (min > 59)
	{
		min -= 60;
		hour++;
		if (hour > 23)
		{
			hour = 0;
			day++;
			week++;

			if (week > 6)
				week = 0;

			if (((mon & 0x01) ^ (mon >> 3)) & 0x0F)
			{
				//1 3 5 7 8 10 12
				if (day > 31)
				{
					day = 1;
					mon++;
				}
			}
			else if (mon == 2)
			{
				//2
				if ((((year & 0x03) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
				{
					//run nian
					if (day > 29)
					{
						day = 1;
						mon++;
					}
				}
				else
				{
					//ping nian
					if (day > 28)
					{
						day = 1;
						mon++;
					}
				}
			}
			else
			{
				//4 6 9 11
				if (day > 30)
				{
					day = 1;
					mon++;
				}
			}

			if (mon > 12)
			{
				mon = 1;
				year++;
			}
		}
	}

	if (mon < 1)
		mon = 1;
	if (mon > 12)
		mon = 12;

	if (day < 1)
		day = 1;
	if (day > 31)
		day = 31;

	if (hour > 23)
		hour = 23;

	if (min > 59)
		min = 59;

	if (sec > 59)
		sec = 59;

	if (week > 6)
		week = 0;

	TimeCur->year = year;
	TimeCur->mon = mon;
	TimeCur->day = day;
	TimeCur->hour = hour;
	TimeCur->min = min;
	TimeCur->sec = sec;
	TimeCur->week = week;
}


/*****************************************************************************/ /*!
* @brief   Rtc run .
*          once per sec , in timer int
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void rtc_time_run_sec(TIME_Type *TimeCur, uint32_t sec_add)
{
	uint8_t mon, day, hour, min, sec, week;
	uint16_t year;

	year = TimeCur->year;
	mon = TimeCur->mon;
	day = TimeCur->day;
	hour = TimeCur->hour;
	min = TimeCur->min;
	sec = TimeCur->sec;
	week = TimeCur->week;

	while (sec_add)
	{
		if (sec + sec_add <= 60)
		{
			sec += sec_add;
			sec_add = 0;
		}
		else
		{
			uint8_t sec_inc;
			sec_inc = 60 - sec;

			sec += sec_inc;
			sec_add -= sec_inc;
		}

		if (sec > 59)
		{
			sec = 0;
			min++;
		}

		if (min > 59)
		{
			min -= 60;
			hour++;
			if (hour > 23)
			{
				hour = 0;
				day++;
				week++;

				if (week > 6)
					week = 0;

				if (((mon & 0x01) ^ (mon >> 3)) & 0x0F)
				{
					//1 3 5 7 8 10 12
					if (day > 31)
					{
						day = 1;
						mon++;
					}
				}
				else if (mon == 2)
				{
					//2
					if ((((year & 0x03) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
					{
						//run nian
						if (day > 29)
						{
							day = 1;
							mon++;
						}
					}
					else
					{
						//ping nian
						if (day > 28)
						{
							day = 1;
							mon++;
						}
					}
				}
				else
				{
					//4 6 9 11
					if (day > 30)
					{
						day = 1;
						mon++;
					}
				}

				if (mon > 12)
				{
					mon = 1;
					year++;
				}
			}
		}
	}

	if (mon < 1)
		mon = 1;
	if (mon > 12)
		mon = 12;

	if (day < 1)
		day = 1;
	if (day > 31)
		day = 31;

	if (hour > 23)
		hour = 23;

	if (min > 59)
		min = 59;

	if (sec > 59)
		sec = 59;

	if (week > 6)
		week = 0;

	TimeCur->year = year;
	TimeCur->mon = mon;
	TimeCur->day = day;
	TimeCur->hour = hour;
	TimeCur->min = min;
	TimeCur->sec = sec;
	TimeCur->week = week;
}


/*****************************************************************************/ /*!
* @brief   Rtc run .
*          once per sec , in timer int
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void rtc_time_run_min(TIME_Type *TimeCur, uint32_t min_add)
{
	uint8_t mon, day, hour, min, sec, week;
	uint16_t year;

	year = TimeCur->year;
	mon = TimeCur->mon;
	day = TimeCur->day;
	hour = TimeCur->hour;
	min = TimeCur->min;
	sec = TimeCur->sec;
	week = TimeCur->week;

	while (min_add)
	{
		if (min + min_add <= 60)
		{
			min += min_add;
			min_add = 0;
		}
		else
		{
			uint8_t min_inc;
			min_inc = 60 - min;

			min += min_inc;
			min_add -= min_inc;
		}

		if (min > 59)
		{
			min -= 60;
			hour++;
			if (hour > 23)
			{
				hour = 0;
				day++;
				week++;

				if (week > 6)
					week = 0;

				if (((mon & 0x01) ^ (mon >> 3)) & 0x0F)
				{
					//1 3 5 7 8 10 12
					if (day > 31)
					{
						day = 1;
						mon++;
					}
				}
				else if (mon == 2)
				{
					//2
					if ((((year & 0x03) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
					{
						//run nian
						if (day > 29)
						{
							day = 1;
							mon++;
						}
					}
					else
					{
						//ping nian
						if (day > 28)
						{
							day = 1;
							mon++;
						}
					}
				}
				else
				{
					//4 6 9 11
					if (day > 30)
					{
						day = 1;
						mon++;
					}
				}

				if (mon > 12)
				{
					mon = 1;
					year++;
				}
			}
		}
	}

	if (mon < 1)
		mon = 1;
	if (mon > 12)
		mon = 12;

	if (day < 1)
		day = 1;
	if (day > 31)
		day = 31;

	if (hour > 23)
		hour = 23;

	if (min > 59)
		min = 59;

	if (sec > 59)
		sec = 59;

	if (week > 6)
		week = 0;

	TimeCur->year = year;
	TimeCur->mon = mon;
	TimeCur->day = day;
	TimeCur->hour = hour;
	TimeCur->min = min;
	TimeCur->sec = sec;
	TimeCur->week = week;
}


/*****************************************************************************/ /*!
* @brief   Rtc run .
*          once per sec , in timer int
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void rtc_time_run_hour(TIME_Type *TimeCur, uint32_t hour_add)
{
	uint8_t mon, day, hour, min, sec, week;
	uint16_t year;

	year = TimeCur->year;
	mon = TimeCur->mon;
	day = TimeCur->day;
	hour = TimeCur->hour;
	min = TimeCur->min;
	sec = TimeCur->sec;
	week = TimeCur->week;

	while (hour_add)
	{
		if (hour + hour_add <= 24)
		{
			hour += hour_add;
			hour_add = 0;
		}
		else
		{
			uint8_t hour_inc;

			hour_inc = 24 - hour;

			hour += hour_inc;
			hour_add -= hour_inc;
		}


		if (hour > 23)
		{
			hour = 0;
			day++;
			week++;

			if (week > 6)
				week = 0;

			if (((mon & 0x01) ^ (mon >> 3)) & 0x0F)
			{
				//1 3 5 7 8 10 12
				if (day > 31)
				{
					day = 1;
					mon++;
				}
			}
			else if (mon == 2)
			{
				//2
				if ((((year & 0x03) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
				{
					//run nian
					if (day > 29)
					{
						day = 1;
						mon++;
					}
				}
				else
				{
					//ping nian
					if (day > 28)
					{
						day = 1;
						mon++;
					}
				}
			}
			else
			{
				//4 6 9 11
				if (day > 30)
				{
					day = 1;
					mon++;
				}
			}

			if (mon > 12)
			{
				mon = 1;
				year++;
			}
		}

	}

	if (mon < 1)
		mon = 1;
	if (mon > 12)
		mon = 12;

	if (day < 1)
		day = 1;
	if (day > 31)
		day = 31;

	if (hour > 23)
		hour = 23;

	if (min > 59)
		min = 59;

	if (sec > 59)
		sec = 59;

	if (week > 6)
		week = 0;

	TimeCur->year = year;
	TimeCur->mon = mon;
	TimeCur->day = day;
	TimeCur->hour = hour;
	TimeCur->min = min;
	TimeCur->sec = sec;
	TimeCur->week = week;
}

/*****************************************************************************/ /*!
* @brief   Time copy .
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void TimeCopy(TIME_Type *pTimeSrc, TIME_Type *pTimeDes)
{
	pTimeDes->year = pTimeSrc->year;
	pTimeDes->mon = pTimeSrc->mon;
	pTimeDes->day = pTimeSrc->day;
	pTimeDes->week = pTimeSrc->week;
	pTimeDes->hour = pTimeSrc->hour;
	pTimeDes->min = pTimeSrc->min;
	pTimeDes->sec = pTimeSrc->sec;
}

/*****************************************************************************/ /*!
* @brief   Time compare .
*
* @param   none
*
* @return  == : 0        >: 1           <: -1
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
int8_t TimeCompare(TIME_Type *pTime1, TIME_Type *pTime2)
{
	uint32_t day1, sec1;
	uint32_t day2, sec2;

	day1 = ((uint32_t)pTime1->year << 16) + ((uint32_t)pTime1->mon << 8) + (uint32_t)pTime1->day;
	sec1 = ((uint32_t)pTime1->hour << 16) + ((uint32_t)pTime1->min << 8) + (uint32_t)pTime1->sec;

	day2 = ((uint32_t)pTime2->year << 16) + ((uint32_t)pTime2->mon << 8) + (uint32_t)pTime2->day;
	sec2 = ((uint32_t)pTime2->hour << 16) + ((uint32_t)pTime2->min << 8) + (uint32_t)pTime2->sec;

	if (day1 == day2)
	{
		if (sec1 == sec2)
		{
			return ((int8_t)(0));
		}
		else if (sec1 > sec2)
		{
			return ((int8_t)(1));
		}
		else
		{
			return ((int8_t)(-1));
		} // End compare - mon
	}
	else if (day1 > day2)
	{
		return ((int8_t)(1));
	}
	else
	{
		return ((int8_t)(-1));
	} // End compare - year
}


/*****************************************************************************/ /*!
* @brief   Time to sig .
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
sig_time_type time_to_sig(TIME_Type *pTimeSrc)
{
	sig_time_type sig;
	int16_t year;

	year = pTimeSrc->year;
	if (year >= rtc_year_base)
	{
		year -= rtc_year_base;
	}

	sig.time.year = year;
	sig.time.mon = pTimeSrc->mon;
	sig.time.day = pTimeSrc->day;
	sig.time.hour = pTimeSrc->hour;
	sig.time.min = pTimeSrc->min;
	sig.time.sec2t = pTimeSrc->sec >> 1;

	return sig;
}

/*****************************************************************************/ /*!
* @brief   sig to time .
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void time_sig_to_time(sig_time_type sig, TIME_Type *pTimeSrc)
{
	pTimeSrc->year = sig.time.year + rtc_year_base;
	pTimeSrc->mon = sig.time.mon;
	pTimeSrc->day = sig.time.day;
	pTimeSrc->hour = sig.time.hour;
	pTimeSrc->min = sig.time.min;
	pTimeSrc->sec = sig.time.sec2t * 2;
}

/*****************************************************************************//*!
* time to bcd
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
bcd_time_type time_sig_to_bcd(sig_time_type sig_time){
	uint8_t u8t;
	bcd_time_type bcd_time;

	u8t = sig_time.time.min;
	bcd_time.time.min = (u8t / 10 << 4) + u8t % 10;

	u8t = sig_time.time.hour;
	bcd_time.time.hour = (u8t / 10 << 4) + u8t % 10;

	u8t = sig_time.time.day;
	bcd_time.time.day = (u8t / 10 << 4) + u8t % 10;

	u8t = sig_time.time.mon;
	bcd_time.time.mon = (u8t / 10 << 4) + u8t % 10;

	u8t = sig_time.time.year;
	bcd_time.time.year = (u8t / 10 << 4) + u8t % 10;

	return bcd_time;
}

/*****************************************************************************//*!
* time to bcd
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
sig_time_type  time_bcd_to_sig(bcd_time_type  bcd_time){
	uint8_t u8t;
	sig_time_type sig_time;

	u8t = bcd_time.time.min;
	sig_time.time.min = (u8t >> 4) * 10 + (u8t & 0x0F);

	u8t = bcd_time.time.hour;
	sig_time.time.hour = (u8t >> 4) * 10 + (u8t & 0x0F);

	u8t = bcd_time.time.day;
	sig_time.time.day = (u8t >> 4) * 10 + (u8t & 0x0F);

	u8t = bcd_time.time.mon;
	sig_time.time.mon = (u8t >> 4) * 10 + (u8t & 0x0F);

	u8t = bcd_time.time.year;
	sig_time.time.year = (u8t >> 4) * 10 + (u8t & 0x0F);

	sig_time.time.sec2t = 0;

	return sig_time;
}

/*****************************************************************************//*!
* time to bcd
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
bcd_time_type time_to_bcd(TIME_Type * time){
	uint8_t u8t;
	bcd_time_type bcd_time;

	u8t = time->min;
	bcd_time.time.min = (u8t / 10 << 4) + u8t % 10;

	u8t = time->hour;
	bcd_time.time.hour = (u8t / 10 << 4) + u8t % 10;

	u8t = time->day;
	bcd_time.time.day = (u8t / 10 << 4) + u8t % 10;

	u8t = time->mon;
	bcd_time.time.mon = (u8t / 10 << 4) + u8t % 10;

	u8t = time->year % 100;
	bcd_time.time.year = (u8t / 10 << 4) + u8t % 10;

	return bcd_time;
}

/*****************************************************************************//*!
* bcd time to ascii
*
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
uint8_t bcd_time_to_ascii(bcd_time_type  bcd_time, uint8_t *des)
{
	uint8_t u8t;

	u8t = bcd_time.time.year;
	*des++ = (u8t >> 4) + 0x30;
	*des++ = (u8t & 0x0f) + 0x30;

	u8t = bcd_time.time.mon;
	*des++ = '-';
	*des++ = (u8t >> 4) + 0x30;
	*des++ = (u8t & 0x0f) + 0x30;

	u8t = bcd_time.time.day;
	*des++ = '-';
	*des++ = (u8t >> 4) + 0x30;
	*des++ = (u8t & 0x0f) + 0x30;

	u8t = bcd_time.time.hour;
	*des++ = ' ';
	*des++ = (u8t >> 4) + 0x30;
	*des++ = (u8t & 0x0f) + 0x30;

	u8t = bcd_time.time.min;
	*des++ = ':';
	*des++ = (u8t >> 4) + 0x30;
	*des++ = (u8t & 0x0f) + 0x30;

	return 14;
}

uint8_t sig_time_to_tm(sig_time_type sig, struct tm *tim)
{
	tim->tm_year = sig.time.year + 100;
	tim->tm_mon = sig.time.mon - 1;
	tim->tm_mday = sig.time.day;
	tim->tm_hour = sig.time.hour;
	tim->tm_min = sig.time.min;
	tim->tm_sec = sig.time.sec2t * 2;

	return 0;
}

uint8_t time_to_tm(TIME_Type *time, struct tm *tim)
{
	tim->tm_year = time->year - 1900;
	tim->tm_mon = time->mon - 1;
	tim->tm_mday = time->day;
	tim->tm_hour = time->hour;
	tim->tm_min = time->min;
	tim->tm_sec = time->sec;

	return 0;
}

time_t sig_time_diff( sig_time_type start, sig_time_type end)
{
	struct tm tm1, tm2;
	time_t t1, t2;

	sig_time_to_tm(start, &tm1);
	sig_time_to_tm(end, &tm2);

	t1 = mktime(&tm1);
	t2 = mktime(&tm2);

	return (time_t)difftime(t2, t1);
}
